<!doctype html>




<html class="theme-next pisces" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>



<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />















  
  
    
  
  <link href="//cdn.jsdelivr.net/fancybox/2.1.5/jquery.fancybox.min.css" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  
    
      
    

    
  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic|Mono:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






  

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.0" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="go语言基础," />





  <link rel="alternate" href="/atom.xml" title="不知归期的故人" type="application/atom+xml" />




  <link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico?v=5.1.0" />






<meta name="description" content="Go并行计算如果说Go有什么让人一见钟情的特性，那大概就是并行计算了吧。 做个题目  如果我们列出10以下所有能够被3或者5整除的自然数，那么我们得到的是3，5，6和9。这四个数的和是23。那么请计算1000以下（不包括1000）的所有能够被3或者5整除的自然数的和。">
<meta name="keywords" content="go语言基础">
<meta property="og:type" content="article">
<meta property="og:title" content="go语言基础--并行计算、包、测试">
<meta property="og:url" content="https://kusole.github.io/2017/07/06/goeasylearn3/index.html">
<meta property="og:site_name" content="不知归期的故人">
<meta property="og:description" content="Go并行计算如果说Go有什么让人一见钟情的特性，那大概就是并行计算了吧。 做个题目  如果我们列出10以下所有能够被3或者5整除的自然数，那么我们得到的是3，5，6和9。这四个数的和是23。那么请计算1000以下（不包括1000）的所有能够被3或者5整除的自然数的和。">
<meta property="og:locale" content="zh-Hans">
<meta property="og:updated_time" content="2018-10-15T08:34:35.368Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="go语言基础--并行计算、包、测试">
<meta name="twitter:description" content="Go并行计算如果说Go有什么让人一见钟情的特性，那大概就是并行计算了吧。 做个题目  如果我们列出10以下所有能够被3或者5整除的自然数，那么我们得到的是3，5，6和9。这四个数的和是23。那么请计算1000以下（不包括1000）的所有能够被3或者5整除的自然数的和。">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    sidebar: {"position":"left","display":"post","offset":12,"offset_float":0,"b2t":false,"scrollpercent":false},
    fancybox: true,
    motion: false,
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://kusole.github.io/2017/07/06/goeasylearn3/"/>





  <title> go语言基础--并行计算、包、测试 | 不知归期的故人 </title>
</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  





  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?124e5902fa6b3c1d89682ed1fa0441ac";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>










  
  
    
  

  <div class="container sidebar-position-left page-post-detail ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">不知归期的故人</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">乘风破浪会有时，直挂云帆济沧海。</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      

      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="popup-trigger">
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br />
            
            搜索
          </a>
        </li>
      
    </ul>
  

  
    <div class="site-search">
      
  <div class="popup search-popup local-search-popup">
  <div class="local-search-header clearfix">
    <span class="search-icon">
      <i class="fa fa-search"></i>
    </span>
    <span class="popup-btn-close">
      <i class="fa fa-times-circle"></i>
    </span>
    <div class="local-search-input-wrapper">
      <input autocapitalize="off" autocomplete="off" autocorrect="off"
             placeholder="搜索..." spellcheck="false"
             type="text" id="local-search-input">
    </div>
  </div>
  <div id="local-search-result"></div>
</div>



    </div>
  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <link itemprop="mainEntityOfPage" href="https://kusole.github.io/2017/07/06/goeasylearn3/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="刘韬">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/uploads/avatar.png">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="不知归期的故人">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                go语言基础--并行计算、包、测试
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2017-07-06T11:40:38+08:00">
                2017-07-06
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/go语言学习笔记/" itemprop="url" rel="index">
                    <span itemprop="name">go语言学习笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="Go并行计算"><a href="#Go并行计算" class="headerlink" title="Go并行计算"></a>Go并行计算</h1><p>如果说Go有什么让人一见钟情的特性，那大概就是并行计算了吧。</p>
<p>做个题目</p>
<blockquote>
<p>如果我们列出10以下所有能够被3或者5整除的自然数，那么我们得到的是3，5，6和9。这四个数的和是23。<br>那么请计算1000以下（不包括1000）的所有能够被3或者5整除的自然数的和。</p>
</blockquote>
<a id="more"></a>
<p>这个题目的一个思路就是：</p>
<p>(1) 先计算1000以下所有能够被3整除的整数的和A，<br>(2) 然后计算1000以下所有能够被5整除的整数和B，<br>(3) 然后再计算1000以下所有能够被3和5整除的整数和C，<br>(4) 使用A+B-C就得到了最后的结果。  </p>
<p>按照上面的方法，传统的方法当然就是一步一步计算，然后再到第(4)步汇总了。</p>
<p>但是一旦有了Go，我们就可以让前面三个步骤并行计算，然后再在第(4)步汇总。</p>
<p>并行计算涉及到一个新的<code>数据类型chan</code>和一个新的<code>关键字go</code>。</p>
<p>先看例子：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">	<span class="string">"time"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">get_sum_of_divisible</span><span class="params">(num <span class="keyword">int</span>, divider <span class="keyword">int</span>, resultChan <span class="keyword">chan</span> <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">	sum := <span class="number">0</span></span><br><span class="line">	<span class="keyword">for</span> value := <span class="number">0</span>; value &lt; num; value++ &#123;</span><br><span class="line">		<span class="keyword">if</span> value%divider == <span class="number">0</span> &#123;</span><br><span class="line">			sum += value</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	resultChan &lt;- sum</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	LIMIT := <span class="number">10</span></span><br><span class="line">	resultChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">int</span>, <span class="number">3</span>)</span><br><span class="line">	t_start := time.Now()</span><br><span class="line">	<span class="keyword">go</span> get_sum_of_divisible(LIMIT, <span class="number">3</span>, resultChan)</span><br><span class="line">	<span class="keyword">go</span> get_sum_of_divisible(LIMIT, <span class="number">5</span>, resultChan)</span><br><span class="line">	<span class="comment">//这里其实那个是被3整除，哪个是被5整除看具体调度方法，不过由于是求和，所以没关系</span></span><br><span class="line">	sum3, sum5 := &lt;-resultChan, &lt;-resultChan</span><br><span class="line"></span><br><span class="line">	<span class="comment">//单独算被15整除的</span></span><br><span class="line">	<span class="keyword">go</span> get_sum_of_divisible(LIMIT, <span class="number">15</span>, resultChan)</span><br><span class="line">	sum15 := &lt;-resultChan</span><br><span class="line"></span><br><span class="line">	sum := sum3 + sum5 - sum15</span><br><span class="line">	t_end := time.Now()</span><br><span class="line">	fmt.Println(sum)</span><br><span class="line">	fmt.Println(t_end.Sub(t_start))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>(1) 在上面的例子中，我们首先定义了一个普通的函数get_sum_of_divisible，这个函数的<code>最后一个参数是一个整型chan类型</code>，这种类型，你可以把它当作一个先进先出的队列。你可以<code>向它写入数据</code>，也可以<code>从它读出数据</code>。它<code>所能接受的数据类型</code>就是<code>由chan关键字后面的类型所决定</code>的。在上面的例子中，我们使用<code>&lt;-</code>运算符将函数计算的结果写入channel。channel是go提供的用来协程之间通信的方式。本例中main是一个协程，三个get_sum_of_divisible调用是协程。要在这四个协程间通信，必须有一种可靠的手段。</p>
<p>(2) 在main函数中，我们使用go关键字来开启并行计算。并行计算是由goroutine来支持的，<code>goroutine</code>又叫做<code>协程</code>，你可以把它看作为比线程更轻量级的运算。开启一个协程很简单，就是<code>go关键字</code>后面<code>跟上所要运行的函数</code>。</p>
<p>(3) 最后，我们要从channel中取出并行计算的结果。使用<code>&lt;-</code>运算符从channel里面取出数据。</p>
<p>在本例中，我们为了演示go并行计算的速度，还引进了time包来计算程序执行时间。在同普通的顺序计算相比，并行计算的速度是非同凡响的。</p>
<p>好了，上面的例子看完，我们来详细讲解Go的并行计算。</p>
<h2 id="Go-Routine-协程"><a href="#Go-Routine-协程" class="headerlink" title="Go Routine 协程"></a>Go Routine 协程</h2><p>所谓协程，就是Go提供的轻量级的独立运算过程，比线程还轻。创建一个协程很简单，就是go关键字加上所要运行的函数。看个例子：<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">list_elem</span><span class="params">(n <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; n; i++ &#123;</span><br><span class="line">		fmt.Println(i)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">go</span> list_elem(<span class="number">10</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>上面的例子是创建一个协程遍历一下元素。但是当你运行的时候，你会<code>发现什么都没有输出</code>！<code>为什么呢？</code><br>因为上面的<code>main函数</code>在<code>创建完协程后</code>就<code>立刻退出</code>了，所以<code>协程</code>还<code>没有来得及运行</code>呢！修改一下：<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">list_elem</span><span class="params">(n <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; n; i++ &#123;</span><br><span class="line">		fmt.Println(i)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">go</span> list_elem(<span class="number">10</span>)</span><br><span class="line">	<span class="keyword">var</span> input <span class="keyword">string</span></span><br><span class="line">	fmt.Scanln(&amp;input)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>这里，我们在main函数创建协程后，要求用户输入任何数据后才退出，这样协程就有了运行的时间，故而输出结果：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">0</span><br><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td></tr></table></figure></p>
<p>其实在开头的例子里面，我们的main函数事实上也被阻塞了，因为<code>sum3, sum5, sum15 := &lt;-resultChan, &lt;-resultChan, &lt;-resultChan</code>这行代码在channel里面没有数据或者数据个数不符的时候，都会阻塞在那里，直到协程结束，写入结果。</p>
<p>不过既然是并行计算，我们还是得看看协程是否真的并行计算了。<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">	<span class="string">"math/rand"</span></span><br><span class="line">	<span class="string">"time"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">list_elem</span><span class="params">(n <span class="keyword">int</span>, tag <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; n; i++ &#123;</span><br><span class="line">		fmt.Println(tag, i)</span><br><span class="line">		tick := time.Duration(rand.Intn(<span class="number">100</span>))</span><br><span class="line">		time.Sleep(time.Millisecond * tick)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">go</span> list_elem(<span class="number">10</span>, <span class="string">"go_a"</span>)</span><br><span class="line">	<span class="keyword">go</span> list_elem(<span class="number">20</span>, <span class="string">"go_b"</span>)</span><br><span class="line">	<span class="keyword">var</span> input <span class="keyword">string</span></span><br><span class="line">	fmt.Scanln(&amp;input)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>输出结果<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">go_a 0</span><br><span class="line">go_b 0</span><br><span class="line">go_a 1</span><br><span class="line">go_b 1</span><br><span class="line">go_a 2</span><br><span class="line">go_b 2</span><br><span class="line">go_b 3</span><br><span class="line">go_b 4</span><br><span class="line">go_a 3</span><br><span class="line">go_b 5</span><br><span class="line">go_b 6</span><br><span class="line">go_a 4</span><br><span class="line">go_a 5</span><br><span class="line">go_b 7</span><br><span class="line">go_a 6</span><br><span class="line">go_a 7</span><br><span class="line">go_b 8</span><br><span class="line">go_b 9</span><br><span class="line">go_a 8</span><br><span class="line">go_b 10</span><br><span class="line">go_b 11</span><br><span class="line">go_a 9</span><br><span class="line">go_b 12</span><br><span class="line">go_b 13</span><br><span class="line">go_b 14</span><br><span class="line">go_b 15</span><br><span class="line">go_b 16</span><br><span class="line">go_b 17</span><br><span class="line">go_b 18</span><br><span class="line">go_b 19</span><br></pre></td></tr></table></figure></p>
<p>在上面的例子中，我们让两个协程在每输出一个数字的时候，随机Sleep了一会儿。如果是并行计算，那么输出是无序的。从上面的例子中，我们可以看出两个协程确实并行运行了。</p>
<h2 id="Channel通道"><a href="#Channel通道" class="headerlink" title="Channel通道"></a>Channel通道</h2><p>Channel提供了<code>协程之间</code>的<code>通信方式</code>以及<code>运行同步机制</code>。</p>
<p>假设训练定点投篮和三分投篮，教练在计数。<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">	<span class="string">"time"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fixed_shooting</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		msg_chan &lt;- <span class="string">"fixed shooting"</span></span><br><span class="line">		fmt.Println(<span class="string">"continue fixed shooting..."</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">count</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		msg := &lt;-msg_chan</span><br><span class="line">		fmt.Println(msg)</span><br><span class="line">		time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> c <span class="keyword">chan</span> <span class="keyword">string</span></span><br><span class="line">	c = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">string</span>)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">go</span> fixed_shooting(c)</span><br><span class="line">	<span class="keyword">go</span> count(c)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> input <span class="keyword">string</span></span><br><span class="line">	fmt.Scanln(&amp;input)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>输出结果为：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">fixed shooting</span><br><span class="line">continue fixed shooting...</span><br><span class="line">fixed shooting</span><br><span class="line">continue fixed shooting...</span><br><span class="line">fixed shooting</span><br><span class="line">continue fixed shooting...</span><br></pre></td></tr></table></figure></p>
<p>我们看到在fixed_shooting函数里面我们将消息传递到channel，然后输出提示信息”continue fixed shooting…”，而在count函数里面，我们从channel里面取出消息输出，然后间隔1秒再去取消息输出。这里面我们可以考虑一下，如果我们不去从channel中取消息会出现什么情况？我们把main函数里面的<code>go count(c)</code>注释掉，然后再运行一下。发现程序再也不会输出消息和提示信息了。这是因为channel中根本就没有信息了，因为<code>如果你要向channel里面写信息</code>，<code>必须有配对的取信息的一端</code>，否则是不会写的。</p>
<p>我们再把三分投篮加上。<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">	<span class="string">"time"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fixed_shooting</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		msg_chan &lt;- <span class="string">"fixed shooting"</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">three_point_shooting</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		msg_chan &lt;- <span class="string">"three point shooting"</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">count</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		msg := &lt;-msg_chan</span><br><span class="line">		fmt.Println(msg)</span><br><span class="line">		time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> c <span class="keyword">chan</span> <span class="keyword">string</span></span><br><span class="line">	c = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">string</span>)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">go</span> fixed_shooting(c)</span><br><span class="line">	<span class="keyword">go</span> three_point_shooting(c)</span><br><span class="line">	<span class="keyword">go</span> count(c)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> input <span class="keyword">string</span></span><br><span class="line">	fmt.Scanln(&amp;input)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>输出结果为：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">fixed shooting</span><br><span class="line">three point shooting</span><br><span class="line">fixed shooting</span><br><span class="line">three point shooting</span><br><span class="line">fixed shooting</span><br><span class="line">three point shooting</span><br></pre></td></tr></table></figure></p>
<p>我们看到程序交替输出定点投篮和三分投篮，这是因为写入channel的信息必须要读取出来，否则尝试再次写入就失败了。</p>
<p>在上面的例子中，我们发现<code>定义一个channel信息变量</code>的方式就是多加一个<code>chan</code>关键字。并且你能够<code>向channel写入数据</code>和<code>从channel读取数据</code>。这里我们还可以设置channel通道的方向。</p>
<h2 id="Channel通道方向"><a href="#Channel通道方向" class="headerlink" title="Channel通道方向"></a>Channel通道方向</h2><p>所谓的<code>通道方向</code>就是<code>写</code>和<code>读</code>。如果我们如下定义</p>
<pre><code>c chan&lt;- string //那么你只能向channel写入数据
</code></pre><p>而这种定义</p>
<pre><code>c &lt;-chan string //那么你只能从channel读取数据
</code></pre><p><code>试图向只读chan变量写入数据或者试图从只写chan变量读取数据都会导致编译错误。</code></p>
<p>如果是默认的定义方式</p>
<pre><code>c chan string //那么你既可以向channel写入数据也可以从channnel读取数据
</code></pre><h2 id="多通道-Select"><a href="#多通道-Select" class="headerlink" title="多通道(Select)"></a>多通道(Select)</h2><p>如果上面的投篮训练现在有两个教练了，各自负责一个训练项目。而且还在不同的篮球场，这个时候很显然，我们一个channel就不够用了。修改一下：<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">	<span class="string">"time"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fixed_shooting</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		msg_chan &lt;- <span class="string">"fixed shooting"</span></span><br><span class="line">		time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">three_point_shooting</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		msg_chan &lt;- <span class="string">"three point shooting"</span></span><br><span class="line">		time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	c_fixed := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">string</span>)</span><br><span class="line">	c_3_point := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">string</span>)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">go</span> fixed_shooting(c_fixed)</span><br><span class="line">	<span class="keyword">go</span> three_point_shooting(c_3_point)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">		<span class="keyword">for</span> &#123;</span><br><span class="line">			<span class="keyword">select</span> &#123;</span><br><span class="line">			<span class="keyword">case</span> msg1 := &lt;-c_fixed:</span><br><span class="line">				fmt.Println(msg1)</span><br><span class="line">			<span class="keyword">case</span> msg2 := &lt;-c_3_point:</span><br><span class="line">				fmt.Println(msg2)</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">	&#125;()</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> input <span class="keyword">string</span></span><br><span class="line">	fmt.Scanln(&amp;input)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>其他的和上面的一样，唯一不同的是我们将定点投篮和三分投篮的消息写入了不同的channel，那么main函数如何知道从哪个channel读取消息呢？使用select方法，select方法依次检查每个channel是否有消息传递过来，如果有就取出来输出。如果同时有多个消息到达，那么select闭上眼睛随机选一个channel来从中读取消息，如果没有一个channel有消息到达，那么select语句就阻塞在这里一直等待。</p>
<p>在某些情况下，比如学生投篮中受伤了，那么就轮到医护人员上场了，教练在一般看看，如果是重伤，教练就不等了，就回去了休息了，待会儿再过来看看情况。我们可以给select加上一个case用来判断是否等待各个消息到达超时。<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">	<span class="string">"time"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fixed_shooting</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> times = <span class="number">3</span></span><br><span class="line">	<span class="keyword">var</span> t = <span class="number">1</span></span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		<span class="keyword">if</span> t &lt;= times &#123;</span><br><span class="line">			msg_chan &lt;- <span class="string">"fixed shooting"</span></span><br><span class="line">		&#125;</span><br><span class="line">		t++</span><br><span class="line">		time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">three_point_shooting</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> times = <span class="number">5</span></span><br><span class="line">	<span class="keyword">var</span> t = <span class="number">1</span></span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		<span class="keyword">if</span> t &lt;= times &#123;</span><br><span class="line">			msg_chan &lt;- <span class="string">"three point shooting"</span></span><br><span class="line">		&#125;</span><br><span class="line">		t++</span><br><span class="line">		time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	c_fixed := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">string</span>)</span><br><span class="line">	c_3_point := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">string</span>)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">go</span> fixed_shooting(c_fixed)</span><br><span class="line">	<span class="keyword">go</span> three_point_shooting(c_3_point)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">		<span class="keyword">for</span> &#123;</span><br><span class="line">			<span class="keyword">select</span> &#123;</span><br><span class="line">			<span class="keyword">case</span> msg1 := &lt;-c_fixed:</span><br><span class="line">				fmt.Println(msg1)</span><br><span class="line">			<span class="keyword">case</span> msg2 := &lt;-c_3_point:</span><br><span class="line">				fmt.Println(msg2)</span><br><span class="line">			<span class="keyword">case</span> &lt;-time.After(time.Second * <span class="number">5</span>):</span><br><span class="line">				fmt.Println(<span class="string">"timeout, check again..."</span>)</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">	&#125;()</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> input <span class="keyword">string</span></span><br><span class="line">	fmt.Scanln(&amp;input)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>在上面的例子中，我们让投篮的人在几次过后挂掉，然后教练就每次等5秒出来看看情况（累死丫的，:-P），因为我们对等待的时间不感兴趣就不用变量存储了，直接<code>&lt;-time.After(time.Second*5)</code>，或许你会奇怪，为什么各个channel消息都没有到达，select为什么不阻塞？就是因为这个time.After，虽然它没有显式地告诉你这是一个channel消息，但是记得么？main函数也是一个channel啊！哈哈！至于time.After的功能实际上让main阻塞了5秒后返回给main的channel一个时间。所以我们在case里面把这个时间消息读出来，select就不阻塞了。</p>
<p>输出结果如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">fixed shooting</span><br><span class="line">three point shooting</span><br><span class="line">fixed shooting</span><br><span class="line">three point shooting</span><br><span class="line">fixed shooting</span><br><span class="line">three point shooting</span><br><span class="line">three point shooting</span><br><span class="line">three point shooting</span><br><span class="line">timeout, check again...</span><br><span class="line">timeout, check again...</span><br><span class="line">timeout, check again...</span><br><span class="line">timeout, check again...</span><br></pre></td></tr></table></figure></p>
<p>这里select还有一个<code>default的选项</code>，如果你指定了default选项，那么当select发现<code>没有消息到达</code>的时候<code>也不会阻塞</code>，直接开始转回去再次判断。</p>
<h2 id="Channel-Buffer通道缓冲区"><a href="#Channel-Buffer通道缓冲区" class="headerlink" title="Channel Buffer通道缓冲区"></a>Channel Buffer通道缓冲区</h2><p>我们定义chan变量的时候，还可以指定它的<code>缓冲区大小</code>。一般我们<code>定义的channel都是同步的</code>，也就是说接受端和发送端彼此等待对方ok才开始。但是如果你给一个channel<code>指定了一个缓冲区</code>，那么<code>消息的发送和接受式异步的</code>，<code>除非channel缓冲区已经满了</code>。</p>
<pre><code>c:=make(chan int, 1)
</code></pre><p>我们看个例子：<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">	<span class="string">"strconv"</span></span><br><span class="line">	<span class="string">"time"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">shooting</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> group = <span class="number">1</span></span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		<span class="keyword">for</span> i := <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++ &#123;</span><br><span class="line">			msg_chan &lt;- strconv.Itoa(group) + <span class="string">":"</span> + strconv.Itoa(i)</span><br><span class="line">		&#125;</span><br><span class="line">		group++</span><br><span class="line">		time.Sleep(time.Second * <span class="number">10</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">count</span><span class="params">(msg_chan <span class="keyword">chan</span> <span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		fmt.Println(&lt;-msg_chan)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> c = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">string</span>, <span class="number">20</span>)</span><br><span class="line">	<span class="keyword">go</span> shooting(c)</span><br><span class="line">	<span class="keyword">go</span> count(c)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">var</span> input <span class="keyword">string</span></span><br><span class="line">	fmt.Scanln(&amp;input)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>输出结果为：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">1:1</span><br><span class="line">1:2</span><br><span class="line">1:3</span><br><span class="line">1:4</span><br><span class="line">1:5</span><br><span class="line">1:6</span><br><span class="line">1:7</span><br><span class="line">1:8</span><br><span class="line">1:9</span><br><span class="line">1:10</span><br><span class="line">2:1</span><br><span class="line">2:2</span><br><span class="line">2:3</span><br><span class="line">2:4</span><br><span class="line">2:5</span><br><span class="line">2:6</span><br><span class="line">2:7</span><br><span class="line">2:8</span><br><span class="line">2:9</span><br><span class="line">2:10</span><br><span class="line">3:1</span><br><span class="line">3:2</span><br><span class="line">3:3</span><br><span class="line">3:4</span><br><span class="line">3:5</span><br><span class="line">3:6</span><br><span class="line">3:7</span><br><span class="line">3:8</span><br><span class="line">3:9</span><br><span class="line">3:10</span><br><span class="line">4:1</span><br><span class="line">4:2</span><br><span class="line">4:3</span><br><span class="line">4:4</span><br><span class="line">4:5</span><br><span class="line">4:6</span><br><span class="line">4:7</span><br><span class="line">4:8</span><br><span class="line">4:9</span><br><span class="line">4:10</span><br></pre></td></tr></table></figure></p>
<p>你可以尝试运行一下，每次都是一下子输出10个数据。然后等待10秒再输出一批。</p>
<h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>并行计算这种特点最适合用来开发网站服务器，因为一般网站服务都是高并发的，逻辑十分复杂。而使用Go的这种特性恰是提供了一种极好的方法。</p>
<h1 id="使用包和测试管理项目"><a href="#使用包和测试管理项目" class="headerlink" title="使用包和测试管理项目"></a>使用包和测试管理项目</h1><p>Go天生就是为了支持良好的项目管理体验而设计的。</p>
<h2 id="包"><a href="#包" class="headerlink" title="包"></a>包</h2><p>在软件工程的实践中，我们会遇到很多功能重复的代码，比如去除字符串首尾的空格。高质量软件产品的特点就是它的部分代码是可以重用的，比如你不必每次写个函数去去除字符串首尾的空格。</p>
<p>我们上面讲过变量，结构体，接口和函数等，事实上所谓的包，就是把一些用的多的这些变量，结构体，接口和函数等统一放置在一个逻辑块中。并且给它们起一个名字，这个名字就叫做包名。</p>
<p>例如我们上面用的最多的fmt包，这个包提供了很多格式化输出的函数，你可以在自己的代码中引用这个包，来做格式化输出，而不用你自己每次去写个函数。一门成熟的语言都会提供齐全的基础功能包供人调用。</p>
<p>使用包有三个好处</p>
<ol>
<li>可以减少函数名称重复，因为不同包中可以存在名称相同的函数。否则得话，你得给这些函数加上前缀或者后缀以示区别。</li>
<li>包把函数等组织在一起，方便你查找和重用。比如你想用Println()函数输出一行字符串，你可以很方便地知道它在fmt包中，直接引用过来用就可以了。</li>
<li>使用包可以加速程序编译。因为包是预编译好的，你改动自己代码得时候，不必每次去把包编译一下。</li>
</ol>
<h2 id="创建包"><a href="#创建包" class="headerlink" title="创建包"></a>创建包</h2><p>我们现在来举个例子，用来演示Go的项目管理。</p>
<p>首先我们在目录<code>/Users/jemy/JemyGraw/GoLang</code>下面创建文件夹<code>pkg_demo</code>。然后在<code>pkg_demo</code>里面创建<code>src</code>文件夹<br>。然后再在<code>main</code>文件夹里面创建<code>main.go</code>文件。另外为了演示包的创建，我们在<code>src</code>目录下面创建文件夹<code>net.duokr</code>，然后再在<code>net.duokr</code>文件夹里面创建<code>math</code>文件夹，这个文件夹名称就是这个文件夹下面go文件的包名称。然后我们再创建一个<code>math_pkg.go</code>文件，之所以取这个名字而不是<code>math.go</code>只是为了说明这个文件名称和包名不需要一致。然后我们还创建了一个<code>math_pkg_test.go</code>文件作为包的测试用例文件。整体结构如下：</p>
<pre><code>.
└── src
    ├── main
    │   ├── build.sh
    │   └── main.go
    └── net.duokr
        └── math
            ├── math_pkg.go
            └── math_pkg_test.go
</code></pre><p>其中build.sh是我们为了编译这个项目而写的脚本，因为编译项目需要几条命令，把它写在脚本文件中方便使用。另外为了能够让build.sh能够执行，使用<code>chmod +x build.sh</code>为它赋予可执行权限。build.bat是Windows下面的编译脚本。<br>我们来看一下<code>math_pkg.go</code>的定义：<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> math</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Add</span><span class="params">(a, b <span class="keyword">int</span>)</span> <span class="title">int</span></span> &#123;</span><br><span class="line">	<span class="keyword">return</span> a + b</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Subtract</span><span class="params">(a, b <span class="keyword">int</span>)</span> <span class="title">int</span></span> &#123;</span><br><span class="line">	<span class="keyword">return</span> a - b</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Multiply</span><span class="params">(a, b <span class="keyword">int</span>)</span> <span class="title">int</span></span> &#123;</span><br><span class="line">	<span class="keyword">return</span> a * b</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Divide</span><span class="params">(a, b <span class="keyword">int</span>)</span> <span class="title">int</span></span> &#123;</span><br><span class="line">	<span class="keyword">if</span> b == <span class="number">0</span> &#123;</span><br><span class="line">		<span class="built_in">panic</span>(<span class="string">"Can not divided by zero"</span>)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> a / b</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>首先是包名，然后是几个函数定义，这里我们会发现这些<code>函数定义首字母都是大写</code>，<code>Go规定了只有首字母大写的函数才能从包导出使用，即其他调用这个包中函数的代码只能调用那些导出的函数</code>。</p>
<p>我们再看一下<code>main.go</code>的定义：<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">"fmt"</span></span><br><span class="line">	math <span class="string">"net.duokr/math"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> a = <span class="number">100</span></span><br><span class="line">	<span class="keyword">var</span> b = <span class="number">200</span></span><br><span class="line"></span><br><span class="line">	fmt.Println(<span class="string">"Add demo:"</span>, math.Add(a, b))</span><br><span class="line">	fmt.Println(<span class="string">"Substract demo:"</span>, math.Subtract(a, b))</span><br><span class="line">	fmt.Println(<span class="string">"Multiply demo:"</span>, math.Multiply(a, b))</span><br><span class="line">	fmt.Println(<span class="string">"Divide demo:"</span>, math.Divide(a, b))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>在main.go里面，我们使用import关键字引用我们自定义的包math，引用的方法是从main包平行的文件夹net.duokr开始，后面跟上包名math。这里面我们给这个长长的包名起了一个别名就叫math。然后分别调用math包里面的函数。</p>
<p>最后我们看一下我们的编译脚本：<br><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> GOPATH=<span class="variable">$GOPATH</span>:/Users/jemy/JemyGraw/GoLang/pkg_demo</span><br><span class="line"><span class="built_in">export</span> GOBIN=/Users/jemy/JemyGraw/GoLang/pkg_demo/bin</span><br><span class="line">go build net.duokr/math</span><br><span class="line">go build main.go</span><br><span class="line">go install main</span><br></pre></td></tr></table></figure></p>
<p>第一行，我们将项目路径加入GOPATH中，这样待会儿编译main.go的时候才能找到我们自定义的包；</p>
<p>第二行，我们设置本项目的安装目录，第五行的命令将编译好的文件放到这个目录下面；</p>
<p>第三行，我们编译我们的自定义包；</p>
<p>第四行，我们编译我们main.go文件；</p>
<p>第五行，将编译好的文件安装到指定目录下。</p>
<p>这里还有一个Windows下面的编译脚本build.bat：<br><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">@<span class="built_in">echo</span> off</span><br><span class="line"><span class="built_in">set</span> GOPATH=GOPATH;C:\JemyGraw\GoLang\pkg_demo</span><br><span class="line"><span class="built_in">set</span> GOBIN=C:\JemyGraw\GoLang\pkg_demo\bin</span><br><span class="line">go build net.duokr\math</span><br><span class="line">go build main.go</span><br><span class="line">go install main</span><br></pre></td></tr></table></figure></p>
<p>好了，运行脚本编译一下，在main文件夹和bin文件夹下面都会生成一个可执行文件。</p>
<p>这个时候文件夹结构为：</p>
<pre><code>.
├── bin
│   └── main
├── pkg
│   └── darwin_386
│       └── net.duokr
│           └── math.a
└── src
    ├── main
    │   ├── build.bat
    │   ├── build.sh
    │   ├── main
    │   └── main.go
    └── net.duokr
        └── math
            ├── math_pkg.go
            └── math_pkg_test.go
</code></pre><p>运行一下，输出结果为：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Add demo: 300</span><br><span class="line">Substract demo: -100</span><br><span class="line">Multiply demo: 20000</span><br><span class="line">Divide demo: 0</span><br></pre></td></tr></table></figure></p>
<p>好了，包的使用介绍完毕，我们再来看一下测试用例怎么写。</p>
<h2 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h2><p>在上面的例子中，我们发现我们自定义的包下面还有一个math_pkg_test.go文件，这个文件包含了本包的一些测试用例。而且Go会把以<code>_test.go</code>结尾的文件当作是测试文件。</p>
<p>测试怎么写，当然是用assert来判断程序的运行结果是否和预期的相同了。</p>
<p>我们来看看这个math包的测试用例。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">package math</span><br><span class="line"></span><br><span class="line">import (</span><br><span class="line">	&quot;testing&quot;</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">func TestAdd(t *testing.T) &#123;</span><br><span class="line">	var a = 100</span><br><span class="line">	var b = 200</span><br><span class="line"></span><br><span class="line">	var val = Add(a, b)</span><br><span class="line">	if val != a+b &#123;</span><br><span class="line">		t.Error(&quot;Test Case [&quot;, &quot;TestAdd&quot;, &quot;] Failed!&quot;)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">func TestSubtract(t *testing.T) &#123;</span><br><span class="line">	var a = 100</span><br><span class="line">	var b = 200</span><br><span class="line"></span><br><span class="line">	var val = Subtract(a, b)</span><br><span class="line">	if val != a-b &#123;</span><br><span class="line">		t.Error(&quot;Test Case [&quot;, &quot;TestSubtract&quot;, &quot;] Failed!&quot;)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">func TestMultiply(t *testing.T) &#123;</span><br><span class="line">	var a = 100</span><br><span class="line">	var b = 200</span><br><span class="line"></span><br><span class="line">	var val = Multiply(a, b)</span><br><span class="line">	if val != a*b &#123;</span><br><span class="line">		t.Error(&quot;Test Case [&quot;, &quot;TestMultiply&quot;, &quot;] Failed!&quot;)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">func TestDivideNormal(t *testing.T) &#123;</span><br><span class="line">	var a = 100</span><br><span class="line">	var b = 200</span><br><span class="line"></span><br><span class="line">	var val = Divide(a, b)</span><br><span class="line">	if val != a/b &#123;</span><br><span class="line">		t.Error(&quot;Test Case [&quot;, &quot;TestDivideNormal&quot;, &quot;] Failed!&quot;)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>将路径切换到测试文件所在目录，运行<code>go test</code>命令，go会自动测试所有的测试用例。</p>
<p>在上面的例子中，测试用例的特点是以函数名以<code>Test</code>开始，而且具有唯一参数<code>t *testing.T</code>。</p>
<h2 id="小结-1"><a href="#小结-1" class="headerlink" title="小结"></a>小结</h2><p>Go提供的包和用例测试是构建优秀的软件产品的基础，只要我们不断学习，努力去做，一定可以做的很好。</p>

      
    </div>

    <div>
      
        

      
    </div>

    <div>
      
        
  <div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center;">
    <div>如果文章对您有帮助，请随意打赏</div>
    <button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
      <span>赏</span>
    </button>
    <div id="QR" style="display: none;">
      
        <div id="wechat" style="display: inline-block">
          <img id="wechat_qr" src="https://i.loli.net/2018/10/15/5bc436827b4bc.png" alt="刘韬 WeChat Pay"/>
          <p>微信打赏</p>
        </div>
      
      
        <div id="alipay" style="display: inline-block">
          <img id="alipay_qr" src="https://i.loli.net/2018/10/15/5bc4368266e2b.png" alt="刘韬 Alipay"/>
          <p>支付宝打赏</p>
        </div>
      
    </div>
  </div>


      
    </div>

    <div>
      
        

      
    </div>

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/go语言基础/" rel="tag"># go语言基础</a>
          
        </div>
      

      
        
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2017/07/06/goeasylearn2/" rel="next" title="go语言基础--函数、指针、结构体、接口">
                <i class="fa fa-chevron-left"></i> go语言基础--函数、指针、结构体、接口
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2017/07/28/basicAlg02/" rel="prev" title="[初等算法]--红黑树">
                [初等算法]--红黑树 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          
  <div class="comments" id="comments">
    
  </div>


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/uploads/avatar.png"
               alt="刘韬" />
          <p class="site-author-name" itemprop="name">刘韬</p>
           
              <p class="site-description motion-element" itemprop="description"></p>
          
        </div>
        <nav class="site-state motion-element">

          
            <div class="site-state-item site-state-posts">
              <a href="/archives">
                <span class="site-state-item-count">26</span>
                <span class="site-state-item-name">日志</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-categories">
              <a href="/categories/index.html">
                <span class="site-state-item-count">10</span>
                <span class="site-state-item-name">分类</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-tags">
              <a href="/tags/index.html">
                <span class="site-state-item-count">12</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        
          <div class="feed-link motion-element">
            <a href="/atom.xml" rel="alternate">
              <i class="fa fa-rss"></i>
              RSS
            </a>
          </div>
        

        <div class="links-of-author motion-element">
          
            
              <span class="links-of-author-item">
                <a href="https://github.com/kusole" target="_blank" title="GitHub">
                  
                    <i class="fa fa-fw fa-github"></i>
                  
                  GitHub
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://www.douban.com/people/83381421/" target="_blank" title="豆瓣">
                  
                    <i class="fa fa-fw fa-twitter"></i>
                  
                  豆瓣
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://www.zhihu.com/people/liu-tao-86-26-47/activities" target="_blank" title="知乎">
                  
                    <i class="fa fa-fw fa-facebook"></i>
                  
                  知乎
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="http://weibo.com/6193724399/profile?topnav=1&wvr=6&is_all=1" target="_blank" title="微博">
                  
                    <i class="fa fa-fw fa-weibo"></i>
                  
                  微博
                </a>
              </span>
            
          
        </div>

        
        

        
        

        


      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Go并行计算"><span class="nav-number">1.</span> <span class="nav-text">Go并行计算</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Go-Routine-协程"><span class="nav-number">1.1.</span> <span class="nav-text">Go Routine 协程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Channel通道"><span class="nav-number">1.2.</span> <span class="nav-text">Channel通道</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Channel通道方向"><span class="nav-number">1.3.</span> <span class="nav-text">Channel通道方向</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#多通道-Select"><span class="nav-number">1.4.</span> <span class="nav-text">多通道(Select)</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Channel-Buffer通道缓冲区"><span class="nav-number">1.5.</span> <span class="nav-text">Channel Buffer通道缓冲区</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#小结"><span class="nav-number">1.6.</span> <span class="nav-text">小结</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#使用包和测试管理项目"><span class="nav-number">2.</span> <span class="nav-text">使用包和测试管理项目</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#包"><span class="nav-number">2.1.</span> <span class="nav-text">包</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#创建包"><span class="nav-number">2.2.</span> <span class="nav-text">创建包</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#测试"><span class="nav-number">2.3.</span> <span class="nav-text">测试</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#小结-1"><span class="nav-number">2.4.</span> <span class="nav-text">小结</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy;  2016 - 
  <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">刘韬</span>

</div>


<div class="Hosted-by">
  由 <a class="theme-link" href="https://pages.github.com/">GitHub Pages</a> 强力驱动
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Pisces
  </a>
</div>

<!-- <div class="powered-by">
  由 <a class="theme-link" href="https://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Pisces
  </a>
</div>

-->


        
<div class="busuanzi-count">
  <script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  

  
</div>


        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  






  
  <script type="text/javascript" src="//cdn.jsdelivr.net/jquery/2.1.3/jquery.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/fastclick/1.0.6/fastclick.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/jquery.lazyload/1.9.3/jquery.lazyload.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/velocity/1.2.3/velocity.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/velocity/1.2.3/velocity.ui.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/fancybox/2.1.5/jquery.fancybox.pack.js"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.0"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.0"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.0"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.0"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.0"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.0"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.0"></script>



  


  




	





  





  





  






  

  <script type="text/javascript">
    // Popup Window;
    var isfetched = false;
    // Search DB path;
    var search_path = "search.xml";
    if (search_path.length == 0) {
      search_path = "search.xml";
    }
    var path = "/" + search_path;
    // monitor main search box;

    function proceedsearch() {
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
        .css('overflow', 'hidden');
      $('.popup').toggle();
    }
    // search function;
    var searchFunc = function(path, search_id, content_id) {
      'use strict';
      $.ajax({
        url: path,
        dataType: "xml",
        async: true,
        success: function( xmlResponse ) {
          // get the contents from search data
          isfetched = true;
          $('.popup').detach().appendTo('.header-inner');
          var datas = $( "entry", xmlResponse ).map(function() {
            return {
              title: $( "title", this ).text(),
              content: $("content",this).text(),
              url: $( "url" , this).text()
            };
          }).get();
          var $input = document.getElementById(search_id);
          var $resultContent = document.getElementById(content_id);
          $input.addEventListener('input', function(){
            var matchcounts = 0;
            var str='<ul class=\"search-result-list\">';
            var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
            $resultContent.innerHTML = "";
            if (this.value.trim().length > 1) {
              // perform local searching
              datas.forEach(function(data) {
                var isMatch = false;
                var content_index = [];
                var data_title = data.title.trim().toLowerCase();
                var data_content = data.content.trim().replace(/<[^>]+>/g,"").toLowerCase();
                var data_url = decodeURIComponent(data.url);
                var index_title = -1;
                var index_content = -1;
                var first_occur = -1;
                // only match artiles with not empty titles and contents
                if(data_title != '') {
                  keywords.forEach(function(keyword, i) {
                    index_title = data_title.indexOf(keyword);
                    index_content = data_content.indexOf(keyword);
                    if( index_title >= 0 || index_content >= 0 ){
                      isMatch = true;
                      if (i == 0) {
                        first_occur = index_content;
                      }
                    }

                  });
                }
                // show search results
                if (isMatch) {
                  matchcounts += 1;
                  str += "<li><a href='"+ data_url +"' class='search-result-title'>"+ data_title +"</a>";
                  var content = data.content.trim().replace(/<[^>]+>/g,"");
                  if (first_occur >= 0) {
                    // cut out 100 characters
                    var start = first_occur - 20;
                    var end = first_occur + 80;
                    if(start < 0){
                      start = 0;
                    }
                    if(start == 0){
                      end = 50;
                    }
                    if(end > content.length){
                      end = content.length;
                    }
                    var match_content = content.substring(start, end);
                    // highlight all keywords
                    keywords.forEach(function(keyword){
                      var regS = new RegExp(keyword, "gi");
                      match_content = match_content.replace(regS, "<b class=\"search-keyword\">"+keyword+"</b>");
                    });

                    str += "<p class=\"search-result\">" + match_content +"...</p>"
                  }
                  str += "</li>";
                }
              })};
            str += "</ul>";
            if (matchcounts == 0) { str = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>' }
            if (keywords == "") { str = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>' }
            $resultContent.innerHTML = str;
          });
          proceedsearch();
        }
      });}

    // handle and trigger popup window;
    $('.popup-trigger').click(function(e) {
      e.stopPropagation();
      if (isfetched == false) {
        searchFunc(path, 'local-search-input', 'local-search-result');
      } else {
        proceedsearch();
      };
    });

    $('.popup-btn-close').click(function(e){
      $('.popup').hide();
      $(".local-search-pop-overlay").remove();
      $('body').css('overflow', '');
    });
    $('.popup').click(function(e){
      e.stopPropagation();
    });
  </script>





  

  

  
  


  

</body>
</html>
